package com.github.data_manage.util

import kotlinx.coroutines.*

/**
 *@author CHN
 *@since 2024-08-11 09:35
 */

suspend fun <T, R> List<T>.mapAsync(mapper: (T) -> R): List<Deferred<R>> {
    if (isEmpty()) return emptyList()
    return coroutineScope {
        map { async { mapper(it) } }
    }
}

fun <T, R> List<T>.mapAsyncBlocking(mapper: (T) -> R): List<R> {
    if (isEmpty()) return emptyList()
    if (size == 1) {
        return listOf(mapper(first()))
    }
    return runBlocking(Dispatchers.Default) {
        map { async { mapper(it) } }.awaitAll()
    }
}

fun <T, R> Iterable<T>.mapAsyncBlocking(mapper: (T) -> R): Iterable<R> {
    return runBlocking(Dispatchers.Default) {
        map { async { mapper(it) } }.awaitAll()
    }
}

fun <T> List<T>.onEachAsyncBlocking(mapper: (T) -> Unit): List<T> {
    if (isEmpty()) return emptyList()
    return runBlocking(Dispatchers.Default) {
        map {
            async {
                mapper(it)
                it
            }
        }.awaitAll()
    }
}


fun <T> Collection<T>.consumeAsyncBlocking(mapper: (T) -> Unit) {
    if (isEmpty()) return
    return runBlocking(Dispatchers.Default) {
        map { launch { mapper(it) } }.joinAll()
    }
}

fun <T> Iterable<T>.foreachAsyncBlocking(mapper: (T) -> Unit) {
    val iterator = this.iterator()
    runBlocking(Dispatchers.Default) {
        val mapJobs = mutableListOf<Job>()
        while (iterator.hasNext()) {
            mapJobs.add(
                launch { mapper(iterator.next()) }
            )
        }
        mapJobs.joinAll()
    }

}

fun <K, V> Map<out K, V>.consumeAsyncBlocking(consumer: (Map.Entry<K, V>) -> Unit) {
    if (isEmpty()) return
    return runBlocking(Dispatchers.Default) {
        entries.map { entry -> async { consumer(entry) } }.awaitAll()
    }
}

suspend fun <K, V> Map<out K, V>.consumeAsync(consumer: (Map.Entry<K, V>) -> Unit) {
    if (isEmpty()) return

    return coroutineScope {
        entries.map { entry -> async { consumer(entry) } }
    }
}

fun <K, V, R> Map<out K, V>.mapAsyncBlocking(transform: (Map.Entry<K, V>) -> R): List<R> {
    if (isEmpty()) return emptyList()
    return runBlocking(Dispatchers.Default) {
        entries.map { entry -> async { transform(entry) } }.awaitAll()
    }
}

suspend fun <K, V, R> Map<out K, V>.mapAsync(transform: (Map.Entry<K, V>) -> R): List<Deferred<R>> {
    if (isEmpty()) return emptyList()
    return coroutineScope {
        entries.map { entry -> async { transform(entry) } }
    }
}

